<?php
	
	/** 
	 * 搭配商品购物车规则 
	 * 主商品 main [co-gid-pid-pmt_id-time()] co-商品di-货品id-优惠id-保存时时间戳
	 * 搭配商品 co [co-gid-pid-pmt_id-time()][coid][copid] coid->搭配组id copid 搭配货品id
	 *
	 */
	 if (!class_exists('mdl_cart'))
	 {
		 $mode_dir =  ((!defined('SHOP_DEVELOPER') || !constant('SHOP_DEVELOPER')) && version_compare(PHP_VERSION,'5.0','>=')?'model_v5':'model');
		 require_once(CORE_DIR.'/'.$mode_dir.'/trading/mdl.cart.php');
	 }
	class mdl_collocAddon extends mdl_cart
	{
		var $coCookie = 'co';

		function _checkMember($aMember)
		{
			$this->memInfo = $aMember;
			if($aMember['member_id'] && $aMember['uname']){
				$this->memberLogin = true;
			}
		}

		function setMemColloc($member_id,$rule)
		{
			$aData['member_id'] = $member_id;
			$aData['addon'] = $rule;
			$sql = "SELECT * FROM sdb_collocate_goods_collocaddon WHERE member_id=".intval($member_id);
			$aRs = $this->db->query($sql);
			$sSql = $this->db->GetUpdateSql($aRs,$aData,true);
			return $this->db->exec($sSql);
		}

		function getMemColloc($member_id)
		{
			$sql = 'SELECT addon from sdb_collocate_goods_collocaddon where member_id='.intval($member_id);
			$aData = $this->db->selectrow($sql);
			return $aData['addon'];
		}

		function splitAddon($sCookie='')
		{
			/*示例：'co-95-347-time(),2_1274670317@267,4-268,5|co-96-541,3_1274670542@246,4-248,5'; co-gid-pid,num_coid@ipid,num
			分解后：[co-95-347]=array(num=>3,1274670542=>array([267]=>4,[268]=>5))
			*/
			if(!$sCookie){
				if($this->memberLogin){
					$sCookie = $this->getMemColloc($this->memInfo['member_id']);
				}else{
					$sCookie = $_COOKIE[$this->coCookie];
				}
			}
			if (!$sCookie) return array();
			$aColloc = array();
			$data = explode('|',$sCookie);
			foreach ($data as $v)
			{
				$items = explode('_',$v);
				list($colPref,$num) = explode(',',$items['0']);	//co-95-347-5-time,2
				$aColloc[$colPref]['num'] = $num;
				unset($items['0']);
				foreach ($items as $key=>$i)
				{
					list($coid,$p) = explode('@',$i);
					$s = explode('-',$p);
					foreach ($s as $value)
					{
						list($pid,$pnum) = explode(',',$value);
						$aColloc[$colPref][$coid][$pid] = $pnum;
					}
				}
			}
			return $aColloc;
		}
		
		/**
		 * 创建搭配商品addon数组信息
		 * @param array $data 示例参见 colloc.php
		 * @return array $aColloc
		 */
		function createColloc($data,&$aErr)
		{
			$aColloc = $this->splitAddon();
			$pid = intval($data['product_id']);
			if (intval($data['product_id'] == 0))
			{
				$objGoods = &$this->system->loadModel('trading/goods');
				$aP = $objGoods->getProducts($data['goods_id']);
				$pid = $aP[0]['product_id'];
			}
			foreach ($data['colloc'] as $key => $var)
			{
				$colPref = $this->coCookie.'-'.$data['goods_id'].'-'.$pid.'-'.$data['pmt_id'].'-'.time();
				if ($this->checkCollocStore($data['goods_id'],$pid,'',$data['num'],$err)){
						$aColloc[$colPref]['num'] = $data['num'];	//主商品数量
					}else return false;
				
				foreach ($var as $k=>$v)
				{
					//$num = isset($aColloc[$colPref][$key][$k])?($aColloc[$colPref][$key][$k]+$v):$v;
					$num = $v;
					//检查搭配商品数量 在设置范围内 则更新addon 否则给出错误信息
					if ($this->checkCollocStore($data['goods_id'],$k,$key,$num,$aErr)){
						$aColloc[$colPref][$key][$k] = $num;
					}else return false;
				}
			}
			//$this->saveCollocCart($aColloc);
			return $aColloc;
		}
		
		/**
		 * 保存搭配商品规则
		 * @param array $aCo $aco[co-95-347-time]=array(num=>3,1274670542=>array([267]=>4,[268]=>5))
		 *
		 */
		function saveCollocCart($aCo)
		{
			foreach ($aCo as $key =>$var)
			{
				$prefix[] = $key.','.$var['num'];
				unset($var['num']);
				foreach ($var as $k =>$value)
				{
					foreach ($value as $pid=>$num)
					{
						$p[] = $pid.','.$num;
					}
					$prefix[] = $k.'@'.implode('-',$p);
				}
				$tmp[] = implode('_',$prefix);
			}
			$ruleStr = implode('|',$tmp);
			if ($this->memberLogin)
			{
				$this->setMemColloc($this->memInfo['member_id'],$ruleStr);
			}
			else
			{
				$this->system->setcookie($this->coCookie,$ruleStr);
			}
			return true;
		}
		
		/** 没有更新规则
		 * 更新搭配商品的addon信息
		 * @param array $data 要更新的数据
		 * @return bool
		 */
		function updateCollocAddon($objType,$key,$num,&$aMsg='',$coid='',$pid='')
		{
			$aCoAddon = $this->splitAddon();
			switch ($objType)
			{
				case 'main':
					list($co,$gid,$pid,$pmt_id,$time) = explode('-',$key);
					// 检查主商品库存
					if ($this->checkCollocStore($gid,$pid,'',$num,$err)){
						$aCoAddon[$key]['num'] = $num;
					}else return false;
					foreach ($aCoAddon[$key] as $k =>$v)
					{
						//过滤主商品数量项
						if ($k && ('num' != $k))
						{
							foreach ($v as $copid=>$conum)
							{
								//检查搭配商品库存
								if ($this->checkCollocStore($gid,$copid,$k,$num,$aMsg)){
									$aCoAddon[$key][$k][$copid] = $num;
								}else return false;
							}
						}
					}
					break;
				case 'co':
					$aCoAddon[$key][$coid][$pid] = $num;
					break;
			}
			//error_log(print_r($aCoAddon,true),3,__FILE__.'.'.__FUNCTION__.'.aCoAddon.log');//alone add
			return $this->saveCollocCart($aCoAddon);
		}
		
		/**
		 * main [co-79-314-5-time]=>3
		 * co [co-79-314-5-time][1274670317][239]=>3
		 *
		 */
		function removeCollocAddon($objType,$key='',$coid='',$pid='')
		{
			if ('all' == $objType)
			{
				if ($this->memberLogin)
				{
					$sql = 'UPDATE sdb_collocate_goods_collocaddon SET addon="" WHERE member_id='.$this->memInfo['member_id'];
					$this->db->exec($sql);
				}
				else
				{
					$this->system->setcookie($this->coCookie,'');
				}
			}
			else
			{
				$aCoAddon = $this->splitAddon();
				if ('main' == $objType)
				{
					unset($aCoAddon[$key]);
				}
				elseif ('co' == $objType)
				{
					unset($aCoAddon[$key][$coid][$pid]);
					/*
					if (empty($aCoAddon[$key][$coid]))
					{
						unset($aCoAddon[$key][$coid]);
					}
					*/				
				}
				$this->saveCollocCart($aCoAddon);
			}
		}
		
		/**
		 * 检查搭配商品的库存
		 * @param string $gid 商品goods_id
		 * @param string $pid 搭配货品的id product_id
		 * @param string $coid 搭配组id
		 * @param int $num 数量
		 * @param string 错误信息
		 * @return bool
		 */
		function checkCollocStore($gid,$pid,$coid='',$num,&$aErr)
		{
			$objProduct = &$this->system->loadModel('goods/products');
			$aStore = $objProduct->getFieldById($pid);
			if(!is_null($aStore['store'])){
				$gStore = intval($aStore['store']) - intval($aStore['freez']);
				if($gStore < $num){
					$aErr = '商品库存不足';
					return false;
					//exit;
				}
			}
			if ($coid)
			{
				$objGoods = $this->system->loadModel('trading/goods');
				$aCollocInfo = unserialize($objGoods->getGoodsMemo($gid,'collocation'));
				if ($num<$aCollocInfo[$coid]['min_num'])
				{
					$aErr = '少于最小购买量';
					return false;
					//exit;
				}
				if ($num>$aCollocInfo[$coid]['max_num'])
				{
					$aErr = '超过最大购买量';
					return false;
					//exit;
				}
			}
			return true;
		}

		function mergeCollocAddon()
		{
			if ($_COOKIE[$this->coCookie])
			{
				$cookieAddon = $_COOKIE[$this->coCookie];
				$dbAddon = $this->getMemColloc();
				$mergeAddon = $cookieAddon.'|'.$dbAddon;
				$this->setMemColloc($mergeAddon);
				$this->system->setcookie($this->coCookie,'');
			}
		}

		/**
		 * 构造shopex标准版的cart规则 返回处理后的collocTrading
		 * @param array &$collocGoods 购物车搭配组信息
		 * @return array $collocTrading 同mdl:trading/sale:getCartObject 返回(处理后)
		 *
		 **/
		function getShopexCartFormat(&$collocGoods)
		{
			$aColloc = $this->splitAddon();
			$objSale = &$this->system->loadModel('trading/sale');
			$objProduct = &$this->system->loadModel('goods/products');
			$objGoods = $this->system->loadModel('trading/goods');
			foreach ($aColloc as $coKey=>$v)
			{
				//构造cart规则数组 以便调用 mdl:trading/sale:getCartObject
				list(,$gid,$pid,$pmt_id,) = explode('-',$coKey);
				$aAddon['g']['cart'][$gid.'-'.$pid.'-na'] = $v['num'];
				$aAddon['g']['pmt'][$gid] = $pmt_id;
				$coInfo = unserialize($objGoods->getGoodsMemo($gid,'collocation'));
				unset($v['num']);	//去掉num项
				foreach ($v as $coid =>$value)
				{
					foreach ($value as $pid =>$pNum)
					{
						$row = $objProduct->getFieldById($pid,array('goods_id'));
						$aAddon['g']['cart'][$row['goods_id'].'-'.$pid.'-na'] = $pNum;
					}
				}
				$trading = $objSale->getCartObject($aAddon,$GLOBALS['runtime']['member_lv'],true);

				$collocGoods[$coKey]['info'] = $coInfo[$coid];		//后台设置的搭配组信息
				$collocGoods[$coKey]['goods'] = array_shift($trading['products']);		//第一项是主商品 其余是搭配商品
				//更新删除用 主商品
				$collocGoods[$coKey]['goods']['key'] = $coKey;
				$collocGoods[$coKey]['goods']['link_key'] = str_replace('-',',',$coKey);

				//搭配组中的商品有优惠 addon中的一块 搭配组id($coid)是同一个且是唯一的
				foreach ($trading['products'] as $tmpK => $p)
				{
					//更新删除用 搭配商品
					$pkey = str_replace('-',',',$coKey);
					$ident_key = $pkey.'@'.$coid.'@'.$p['product_id'];
					$trading['products'][$tmpK]['link_key'] = $ident_key;
					$trading['products'][$tmpK]['key'] = $coid;
					if ('minus' == $coInfo[$coid]['set_price'])
					{						
						$pmt_price = $coInfo[$coid]['price']*$p['nums'];
						$trading['products'][$tmpK]['_pmt']['price'] -= $coInfo[$coid]['price'];
						$trading['products'][$tmpK]['_pmt']['amount'] -= $pmt_price;
					}
					else
					{
						if ($discount = $rows[$coid]['price'])
						{
							$pmt_price = $discount*$p['nums'];
							$trading['products'][$tmpK]['_pmt']['price'] *= $discount;
							$trading['products'][$tmpK]['_pmt']['amount'] *= $discount*$p['nums'];
						}
					}
					$pmt_amount += $pmt_price;	//搭配组中的优惠总价
					$pmt_weight += $p['weight']*$p['nums'];	//搭配组中的商品重量
					$pmt_score += $p['score']*$p['nums'];	//搭配组中的商品积分
				}
				//相应的减去搭配组中的优惠总额
				$trading['totalPrice'] -= $pmt_amount;
				$trading['pmt_g']['totalPrice'] -= $pmt_amount;
				$trading['pmt_o']['totalPrice'] -= $pmt_amount;
				//相应的加上搭配组中的商品总重量
				$trading['weight'] += $pmt_weight;
				//相应的加上搭配组中的积分
				$trading['totalGainScore'] += $pmt_score;
				$trading['pmt_b']['totalGainScore'] += $pmt_score;
				$trading['pmt_g']['totalGainScore'] += $pmt_score;
				$trading['pmt_o']['totalGainScore'] += $pmt_score;
				$trading['totalScore'] += $pmt_score;
				$collocTrading[$coKey] = $trading;
				$collocGoods[$coKey]['products'] = $trading['products'];
			}
			return $collocTrading;
		}

		function mergeCollocTrading($collocTrading,$mlvid,$showPromotion=false,$mergeProducts=false)
		{
			//error_log(print_r(func_get_args(),true),3,__FILE__.'.'.__FUNCTION__.'.func_get_args.log');//alone add
			//取出第一项作为主数组 一般为mdl:trading/cart:getCartObject返回值 所以次序很重要
			$tmpTrading = array_shift($collocTrading);
			foreach ($collocTrading as $v)
			{
				$tmpTrading['weight'] += $v['weight'];
				$tmpTrading['totalPrice'] += $v['totalPrice'];
				$tmpTrading['totalGainScore'] += $v['totalGainScore'];
				$tmpTrading['totalScore'] += $v['totalScore'];
				$tmpTrading['totalConsumeScore'] += $v['totalConsumeScore'];
				$tmpTrading['exemptFreight'] = ($tmpTrading['exemptFreight'] || $v['exemptFreight']);
				$tmpTrading['pmt_b']['totalPrice'] += $v['pmt_b']['totalPrice'];
				$tmpTrading['pmt_b']['totalGainScore'] += $v['pmt_b']['totalGainScore'];
				$tmpTrading['pmt_g']['totalPrice'] += $v['pmt_b']['totalPrice'];
				$tmpTrading['pmt_g']['totalGainScore'] += $v['pmt_b']['totalGainScore'];
				$tmpTrading['pmt_o']['totalPrice'] += $v['pmt_b']['totalPrice'];
				$tmpTrading['pmt_o']['totalGainScore'] += $v['pmt_b']['totalGainScore'];
				$tmpTrading['gift_p'] = array_merge2((array)$tmpTrading['gift_p'],(array)$v['gift_p']);	//数组相加 键名是对应的id 相同则合并
				$tmpTrading['coupon_p'] = array_merge2((array)$tmpTrading['coupon_p'],(array)$v['coupon_p']);	//数组相加 键名是对应的id 相同则合并
				$tmpTrading['products'] = array_merge($tmpTrading['products'],$v['products']);
			}
			if ($mergeProducts)
			{
				$this->mergeTradingProducts($tmpTrading['products']);
			}
			return $this->applyPmt(&$tmpTrading,$mlvid,$showPromotion);
		}

		function mergeTradingProducts(&$aProducts)
		{
			//逐次遍历
			sort($aProducts);
			$lenght = count($aProducts);
			for ($i=0;$i<$lenght;$i++)
			{
				for ($j=$i+1;$j<$lenght;$j++)
				{
					if ($aProducts[$i]['pid'] == $aProducts[$j]['pid'])
					{
						$aProducts[$i]['nums'] += $aProducts[$j]['nums'];
						$aProducts[$i]['amount'] += $aProducts[$j]['amount'];
						$aProducts[$i]['_pmt']['amount'] += $aProducts[$j]['_pmt']['amount'];
						$dropKey[] = $j;
					}
				}
			}
			foreach ($aProducts as $k =>$v)
			{
				if (in_array($k,$dropKey))
				{
					unset($aProducts[$k]);
				}
			}
		}

		function applyPmt(&$trading,$mlvid,$showPromotion=false)
		{
			$objSale = &$this->system->loadModel('trading/sale');
			$oPromotion = &$this->system->loadModel('trading/promotion');
            if ($showPromotion) {
                //$oPromotion->apply_pdt_pmt($trading, $mlvid);        //商品促销
                $oPromotion->apply_order_pmt($trading, $mlvid);        //订单促销
            }

            $trading['totalGainScore'] = intval($trading['totalGainScore']);
            $trading['totalConsumeScore'] = intval($trading['totalConsumeScore']);
            $trading['totalScore'] = $trading['totalGainScore'] - $trading['totalConsumeScore'];
            $objSale->mount_gift_p($trading);
            $objSale->mount_coupon($trading);
            $objSale->mount_pmt_o($trading);
            return $trading;
		}

		function getCheckout(&$aCart, $aMember, $currency)
		{
			$trading = $this->checkoutInfo($aCart, $aMember);
			$gtype = &$this->system->loadModel('goods/gtype');
			foreach($trading['products'] as $p){
				if($p['goods_id'] > 0) $aP[] = $p['goods_id'];
			}
			if(!empty($aP) || $trading['package'] || $trading['gift_e']){    //todo 需要处理捆绑商品的配送问题
				if(!empty($aP)){
					$deliverInfo = $gtype->deliveryInfo($aP);
					$aOut['has_physical'] = $deliverInfo['physical'];
				}else{
					$aOut['has_physical'] = 1;
				}
				foreach($trading['products'] as $product){
					if($deliverInfo['custom'][$product['type_id']]){
						$aOut['minfo'][$product['product_id']] = array(
								'goods_id' => $product['goods_id'],
								'nums' => $product['nums'],
								'name' => $product['name'],
								'minfo' => &$deliverInfo['custom'][$product['type_id']]);
					}
				}
				$oDly = &$this->system->loadModel('trading/delivery');
				if($area = $oDly->getDlAreaList()){
					foreach($area as $a){
						$aOut['areas'][$a['area_id']]=$a['name']; 
					}
				}
			}
			
			$payment = &$this->system->loadModel('trading/payment');
			$oCur = &$this->system->loadModel('system/cur');
			$currency = $oCur->getcur($currency, true);

			$oMem = &$this->system->loadModel('member/member');
			$trading['receiver'] = $oMem->getDefaultAddr($aMember['member_id']);
			$trading['receiver']['email'] = $aMember['email'];

			$aOut['currencys'] = $oCur->curAll();
			$aOut['currency'] = $currency['cur_code'];
			$aOut['payments'] = $payment->getByCur($currency['cur_code']);
			$aOut['trading'] = $trading;
			return $aOut;
		}

		function checkoutInfo(&$aCart, &$aMember, $aParam=null)
		{
			$sale = &$this->system->loadModel('trading/sale');
			$trading = $sale->getCartObject($aCart,$aMember['member_lv_id'],true);
			/* alone add start */
			if ($this->splitAddon())
			{
				$tmpProducts = $trading['products'];	//记录原有商品
				$tmpTrading = $this->getShopexCartFormat($collocGoods);
				$collocTrading = $this->mergeCollocTrading($tmpTrading,$GLOBALS['runtime']['member_lv'],true,true);
				$mergeTrading[] = $trading;
				$mergeTrading[] = $collocTrading;
				$trading = $this->mergeCollocTrading($mergeTrading,$GLOBALS['runtime']['member_lv'],true,true);
				$trading['products'] = $tmpProducts;		//复原原有商品
			}
			/* alone add end */

			$trading['total_amount'] = $trading['totalPrice'];
			if($aParam['shipping_id']){
				$shipping = &$this->system->loadModel('trading/delivery');
				$aShip = $shipping->getDlTypeByArea($aParam['area'], 0, $aParam['shipping_id']);
				if($trading['exemptFreight'] == 1){
					$trading['cost_freight'] = 0;
				}else{
					$trading['cost_freight'] = cal_fee($aShip[0]['expressions'],$trading['weight'],$trading['pmt_b']['totalPrice'],$aShip[0]['price']);
				}
				$trading['shipping_id'] = $aParam['shipping_id'];
				if($aParam['is_protect'] == 'true' && $aShip[0]['protect']){
					$trading['is_protect'] = 1;
					$trading['cost_protect'] = max($aShip[0]['protect_rate']*$trading['totalPrice'], $aShip[0]['minprice']);
				}
				$trading['total_amount'] += $trading['cost_freight']+$trading['cost_protect'];
			}
			if($this->system->getConf('site.trigger_tax')){
				$trading['is_tax'] = 1;
				if(isset($aParam['is_tax']) && $aParam['is_tax'] == 'true'){
					$trading['tax_checked'] = 'checked';
					$trading['cost_tax'] = $trading['totalPrice'] * $this->system->getConf('site.tax_ratio');
					$trading['total_amount'] += $trading['cost_tax'];
				}
				$trading['tax_rate'] = $this->system->getConf('site.tax_ratio');
			}

			if($aParam['payment']){
				$payment = &$this->system->loadModel('trading/payment');
				$aPay = $payment->getPaymentById($aParam['payment']);
				$config=unserialize($aPay['config']);
				if ($config['method']<>2)
					$trading['cost_payment'] = $aPay['fee'] * $trading['total_amount'];
				else
					$trading['cost_payment'] = $config['fee'];
				$trading['total_amount'] += $trading['cost_payment'];
			}

			$trading['score_g'] = $trading['pmt_b']['totalGainScore'];
			$trading['pmt_amount'] = $trading['pmt_b']['totalPrice'] - $trading['totalPrice'];
			$trading['member_id'] = $aMember['member_id'];
			
			$order = &$this->system->loadModel('trading/order');
			$newNum = $order->getOrderDecimal($trading['total_amount']);
			$trading['discount'] = $trading['total_amount'] - $newNum;
			$trading['total_amount'] = $newNum;
			$oCur = &$this->system->loadModel('system/cur');
			$currency = $oCur->getcur($aParam['cur']);
			if($currency['cur_code']){
				$trading['cur_rate'] = $currency['cur_rate'];
			}else{
				$trading['cur_rate'] = 1;
			}
			$trading['final_amount'] = $newNum * $trading['cur_rate'];
			$trading['cur_sign'] = $currency['cur_sign'];
			$trading['cur_display'] = $this->system->request['cur'];
			$trading['cur_code'] = $currency['cur_code'];
			return $trading;
		}
	}
?>